<!DOCTYPE HTML>
<html>
  <head>
    <script type="text/javascript">
      function crossxhr(details) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange = function(){
          var responseState = {
            responseXML:(xmlhttp.readyState == 4 ? xmlhttp.responseXML : ''),
            responseText:(xmlhttp.readyState == 4 ? xmlhttp.responseText : ''),
            readyState:xmlhttp.readyState,
            responseHeaders:(xmlhttp.readyState == 4 ? xmlhttp.getAllResponseHeaders() : ''),
            status:(xmlhttp.readyState == 4 ? xmlhttp.status : 0),
            statusText:(xmlhttp.readyState == 4 ? xmlhttp.statusText : ''),
            finalUrl:(xmlhttp.readyState == 4 ? xmlhttp.finalUrl : '')
          };
          if (details["onreadystatechange"]) {
            details["onreadystatechange"](responseState);
          }
          if (xmlhttp.readyState == 4) {
            if (details["onload"] && xmlhttp.status >= 200 && xmlhttp.status < 300) {
              details["onload"](responseState);
            }
            if (details["onerror"] && (xmlhttp.status < 200 || xmlhttp.status >= 300)) {
              details["onerror"](responseState);
            }
          }
        };
        try {
          xmlhttp.open(details.method, details.url);
        } catch(e) {
          if(details["onerror"]) {
            details["onerror"]({responseXML:'',responseText:'',readyState:4,responseHeaders:'',status:403,statusText:'Forbidden'});
          }
          return false;
        }
        if (details.headers) {
          for (var prop in details.headers) {
            xmlhttp.setRequestHeader(prop, details.headers[prop]);
          }
        }
        xmlhttp.send((typeof(details.data) != 'undefined') ? details.data : null);
        return true
      }
      
      function xhr(e, details) {
        var onreadystatechange = details.onreadystatechange; // the id
        if (details.onreadystatechange) {
          details.onreadystatechange = function(response){
            call(e, onreadystatechange, [response]);
          };
        }
        var onload = details.onload; // the id
        if (details.onload) {
          details.onload = function(response){
            call(e, onload, [response]);
          };
        }
        var onerror = details.onerror; // the id
        if (details.onerror) {
          details.onerror = function(response){
            call(e, onerror, [response]);
          };
        }
        
        crossxhr(details);
      }
      
      function save(e, name, value) {
        if (typeof value === "object")
          value = JSON.stringify(value);
        return localStorage[name] = value;
      }
      
      function load(e, name) {
        return (!localStorage[name] || localStorage[name] === "[object Object]" ? {} : localStorage[name]);
      }
      
      function nameToFunction(name) {
        if (name === "xhr") return xhr;
        if (name === "save") return save;
        if (name === "load") return load;
        return this[name];
      }
      
      function call(e, id, args) {
        if (id !== null) {
          e.target.page.dispatchMessage("call", JSON.stringify({ id: id, arguments: args, level: "safe" }));
        }
      }
      
      function functionListener(e) {
        if (e.name !== "call") return;
        var data = JSON.parse(e.message);
        if (data.level === "safe") return;
        
        var func = nameToFunction(data.method);
        if (typeof func === "function") {
          var args = [e].concat(data.arguments);
          var returnValue = func.apply(this, args);
          call(e, data.id, [returnValue]);
        }
      }
      
      safari.application.addEventListener("message", functionListener, false); // Attaching a listener
    </script>
  </head>
  <body></body>
</html>